from machine import reset, Pin
from time import sleep
import usocket as soc
import gc
import network
import camera
import _thread

# 摄像头配置常量
# 来自config.py的核心配置
PIN_PWDN    = const(0)
PIN_RESET   = const(1)
PIN_XCLK    = const(2)
PIN_SIOD    = const(3)
PIN_SIOC    = const(4)
PIN_D7      = const(5)
PIN_D6      = const(6)
PIN_D5      = const(7)
PIN_D4      = const(8)
PIN_D3      = const(9)
PIN_D2      = const(10)
PIN_D1      = const(11)
PIN_D0      = const(12)
PIN_VSYNC   = const(13)
PIN_HREF    = const(14)
PIN_PCLK    = const(15)
XCLK_MHZ    = const(16)
PIXFORMAT   = const(17)
FRAMESIZE   = const(18)
JPEG_QUALITY= const(19)
FB_COUNT    = const(20)

# AI - Thinker esp32 - cam 配置
ai_thinker = {
    PIN_PWDN:32,
    PIN_RESET:-1,
    PIN_XCLK:0,
    PIN_SIOD:26,
    PIN_SIOC:27,
    PIN_D7:35,
    PIN_D6:34,
    PIN_D5:39,
    PIN_D4:36,
    PIN_D3:21,
    PIN_D2:19,
    PIN_D1:18,
    PIN_D0:5,
    PIN_VSYNC:25,
    PIN_HREF:23,
    PIN_PCLK:22,
    XCLK_MHZ:16,
    PIXFORMAT:5,
    FRAMESIZE:10,
    JPEG_QUALITY:10,
    FB_COUNT:1, 
}


S3_IP      = '192.168.137.100'
S3_PORT    = 8080
_TX_SOCK   = None
_TX_FRAME_CNT = 0              # 已发送帧计数

# HTML和HTTP头定义
# 来自html.py的核心部分
pg = {
    'foto':'''<!DOCTYPE html>
<html>
<head>
<title>ESP32 Camera Live Stream</title>
<link rel="icon" href="">
</head>
<body>
  <div style="display:flex; margin-top: 5%%; justify-content:center; align-items:center; height:80vh;">
    <img src="/live" style="max-height:100%%;"/>
  </div>
</body>
</html>
''',
}

hdr = {
    'foto': """HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Connection: Closed
Content-Length: %d""",
    'stream': """HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace; boundary=frame
Connection: keep-alive
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Expires: Thu, Jan 01 1970 00:00:00 GMT
Pragma: no-cache""",
    'frame': """--frame
Content-Type: image/jpeg""",
}

# WiFi配置
# 来自wifi.py的核心部分
class Sta:
    AP = "LAPTOP-D3RPTUAA 6358"
    PWD = "19234949992.ch"

    def __init__(self, ap='', pwd=''):
        network.WLAN(network.AP_IF).active(False)  # 禁用接入点模式
        self.wlan = network.WLAN(network.STA_IF)
        self.wlan.active(True)
        if ap == '':
            self.ap = Sta.AP
            self.pwd = Sta.PWD
        else:
            self.ap = ap
            self.pwd = pwd

    def connect(self):
        if not self.wlan.isconnected():
            print(f"连接到 {self.ap}...")
            self.wlan.connect(self.ap, self.pwd)

    def wait(self):
        cnt = 30
        while cnt > 0 and not self.wlan.isconnected():
            print("等待WiFi连接...")
            sleep(1)
            cnt -= 1
        if self.wlan.isconnected():
            print("WiFi已连接")
            print('网络配置:', self.wlan.ifconfig())
            return self.wlan.ifconfig()[0]
        else:
            print("WiFi连接失败")
            return None

# 服务器和路由处理
# 来自webcam.py和site.py的核心部分
ip = ''
camera_instance = None

def clean_up(cs):
    try:
        cs.close()
    except:
        pass
    del cs
    gc.collect()

def handle_root(cs):
    p = pg['foto']
    ln = len(p) + 2
    cs.write(b'%s\r\n\r\n%s\r\n' % (hdr['foto'] % ln, p))

def handle_live(cs):
    cs.write(b'%s\r\n\r\n' % hdr['stream'])
    cs.setblocking(True)
    try:
        while True:
            cs.write(b'%s\r\n\r\n' % hdr['frame'])
            cs.write(camera_instance.capture())
            cs.write(b'\r\n')
    except Exception as e:
        print(f"错误: {e}")
    clean_up(cs)

def route(cs, path):
    if path == '/' or path == '/webcam':
        handle_root(cs)
    elif path == '/live':
        handle_live(cs)
    else:
        # 忽略其他请求
        pass
    clean_up(cs)

def start_server(port=80):
    global ip
    ss = soc.socket(soc.AF_INET, soc.SOCK_STREAM)
    ss.setsockopt(soc.SOL_SOCKET, soc.SO_REUSEADDR, 1)
    ss.bind(('0.0.0.0', port))
    ss.listen(1)
    print(f"服务器启动在端口 {port}")
    print(f"访问 http://{ip} 查看实时画面")

    while True:
        try:
            cs, ca = ss.accept()
            cs.settimeout(10.0)
            r = cs.recv(1024)
            ms = r.decode()
            rq = ms.split(' ')
            if len(rq) >= 2:
                path = rq[1]
                print(f"请求: {path} 来自 {ca}")
                route(cs, path)
            else:
                clean_up(cs)
        except Exception as e:
            print(f"服务器错误: {e}")
            clean_up(cs)

def _tx_init():
    """建立到 ESP32-S3 的 TCP 连接（全局只连一次）"""
    global _TX_SOCK
    _TX_SOCK = soc.socket(soc.AF_INET, soc.SOCK_STREAM)
    _TX_SOCK.settimeout(3.0)
    try:
        _TX_SOCK.connect((S3_IP, S3_PORT))
        print('[TX] 已连接 ESP32-S3  %s:%d' % (S3_IP, S3_PORT))
    except Exception as e:
        print('[TX] 连接失败: %s' % e)
        _TX_SOCK.close()
        _TX_SOCK = None

def _tx_send_frame(jpeg):
    """把一帧 JPEG 发出去，并打印传输状态"""
    global _TX_FRAME_CNT, _TX_SOCK
    if _TX_SOCK is None:
        return
    try:
        _TX_SOCK.write(b'--frame\r\n')
        _TX_SOCK.write(b'Content-Type: image/jpeg\r\n')
        _TX_SOCK.write(b'Content-Length: %d\r\n\r\n' % len(jpeg))
        _TX_SOCK.write(jpeg)
        _TX_SOCK.write(b'\r\n')
        _TX_FRAME_CNT += 1
        if _TX_FRAME_CNT % 30 == 0:               # 每 30 帧打印一次
            print('[TX] 已发送 %d 帧' % _TX_FRAME_CNT)
    except Exception as e:
        print('[TX] 发送失败: %s  重连...' % e)
        _TX_SOCK.close()
        _TX_SOCK = None
        _tx_init()

def _tx_thread():
    """后台线程：不断抓取帧并转发"""
    _tx_init()
    while True:
        if _TX_SOCK:
            _tx_send_frame(camera.capture())
        else:
            sleep(2)         # 等待重连
        sleep(0.056)         # 约 18 FPS

# 主程序初始化
def main():
    global ip, camera_instance
    gc.enable()

    # 配置摄像头
    def configure_camera(cam, config):
        for key, val in config.items():
            cam.conf(key, val)

    configure_camera(camera, ai_thinker)
    camera.conf(XCLK_MHZ, 16)

    # 初始化摄像头
    cam_ready = False
    for i in range(5):
        cam_ready = camera.init()
        print(f"摄像头准备状态: {cam_ready}")
        if cam_ready:
            break
        sleep(2)
    if not cam_ready:
        print("摄像头初始化失败")
        reset()

    # 配置摄像头参数
    camera.framesize(6)
    camera.quality(10)
    camera.brightness(0)
    camera.contrast(0)
    camera.speffect(0)
    camera.flip(0)
    camera_instance = camera

    # 连接WiFi
    w = Sta()
    w.connect()
    ip = w.wait()
    if not ip:
        reset()
    
    # TCP发送线程
    _thread.start_new_thread(_tx_thread, ())
    
    # 启动服务器
    start_server()

if __name__ == "__main__":
    main()

